#include <iostream>
#include "../../comlink/link/link.h"
#include "../../comlink/linkslist/linkslist.h"
#include "../../comlink/linkcontrol/linkcontrol.h"


int main(int argc, char ** argv)
{
  // Link Control Pointer
  LinkControl * Processor1;
  LinkControl * Processor2;
  LinkControl * Processor3;

  bool * tempLinkBuff;
  
  int outerLoop, innerLoop;

  // Create a linked list for holding the physical links
  LinksList * linkHolder = new LinksList();

  Processor1 = new LinkControl();
  Processor2 = new LinkControl();
  Processor3 = new LinkControl();

  tempLinkBuff = linkHolder->CreateNewLink();
  Processor1->SetLinkToNeighbor(LinkControl::NORTH, tempLinkBuff);
  Processor2->SetLinkToNeighbor(LinkControl::SOUTH, tempLinkBuff);

  tempLinkBuff = linkHolder->CreateNewLink();
  Processor1->SetLinkToNeighbor(LinkControl::EAST, tempLinkBuff);
  tempLinkBuff = linkHolder->CreateNewLink();
  Processor3->SetLinkToNeighbor(LinkControl::WEST, tempLinkBuff);

  Processor1->SetLinkToNeighbor(LinkControl::NORTHEAST, linkHolder->CreateNewLink());
  Processor1->SetLinkToNeighbor(LinkControl::NORTHWEST, linkHolder->CreateNewLink());
  Processor1->SetLinkToNeighbor(LinkControl::SOUTH, linkHolder->CreateNewLink());
  Processor1->SetLinkToNeighbor(LinkControl::SOUTHEAST, linkHolder->CreateNewLink());
  Processor1->SetLinkToNeighbor(LinkControl::SOUTHWEST, linkHolder->CreateNewLink());
  Processor1->SetLinkToNeighbor(LinkControl::WEST, linkHolder->CreateNewLink());

  Processor2->SetLinkToNeighbor(LinkControl::NORTH, linkHolder->CreateNewLink());
  Processor2->SetLinkToNeighbor(LinkControl::NORTHEAST, linkHolder->CreateNewLink());
  Processor2->SetLinkToNeighbor(LinkControl::NORTHWEST, linkHolder->CreateNewLink());
  Processor2->SetLinkToNeighbor(LinkControl::SOUTHEAST, linkHolder->CreateNewLink());
  Processor2->SetLinkToNeighbor(LinkControl::SOUTHWEST, linkHolder->CreateNewLink());
  Processor2->SetLinkToNeighbor(LinkControl::WEST, linkHolder->CreateNewLink());
  Processor2->SetLinkToNeighbor(LinkControl::EAST, linkHolder->CreateNewLink());
  
  Processor3->SetLinkToNeighbor(LinkControl::NORTH, linkHolder->CreateNewLink());
  Processor3->SetLinkToNeighbor(LinkControl::NORTHEAST, linkHolder->CreateNewLink());
  Processor3->SetLinkToNeighbor(LinkControl::NORTHWEST, linkHolder->CreateNewLink());
  Processor3->SetLinkToNeighbor(LinkControl::SOUTHEAST, linkHolder->CreateNewLink());
  Processor3->SetLinkToNeighbor(LinkControl::SOUTHWEST, linkHolder->CreateNewLink());
  Processor3->SetLinkToNeighbor(LinkControl::SOUTH, linkHolder->CreateNewLink());
  Processor3->SetLinkToNeighbor(LinkControl::EAST, linkHolder->CreateNewLink());

  Processor1->SetHostAddress(100);
  Processor2->SetHostAddress(200);
  Processor3->SetHostAddress(300);



  outerLoop = 0;
  // check to make sure all links are active
  while(!Processor1->AreAllLinksComplete() ||
        !Processor2->AreAllLinksComplete() ||
        !Processor3->AreAllLinksComplete())
  {
    /* 12 clock cycles
     * not actual simulated
     * */
    std::cout << std::endl << "Clocking: " << outerLoop++ << std::endl << std::endl;
    for(innerLoop = 0; innerLoop < 13; innerLoop++)
    {
      Processor1->ClockLinkControl();
      Processor2->ClockLinkControl();
      Processor3->ClockLinkControl();
    }

    std::cout << std::endl << std::endl;
    std::cout << "Processor 1 Complete? " << Processor1->AreAllLinksComplete() << std::endl;
    std::cout << "Processor 2 Complete? " << Processor2->AreAllLinksComplete() << std::endl;
    std::cout << "Processor 3 Complete? " << Processor3->AreAllLinksComplete() << std::endl;
    std::cout << std::endl << std::endl;

  }

  std::cout << std::endl << std::endl << "Printing Report" << std::endl << std::endl;
  std::cout << "Printing Processor 1" << std::endl;
  Processor1->PrintLinksBuildLabel();
  std::cout << "Printing Processor 2" << std::endl;
  Processor2->PrintLinksBuildLabel();
  std::cout << "Printing Processor 3" << std::endl;
  Processor3->PrintLinksBuildLabel();
  std::cout << std::endl << std::endl;

  // reclaima and release memory
  delete Processor1;
  delete Processor2;
  delete Processor3;
  delete linkHolder;

  return 1;
}
